home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / progutil / iostream.zoo / src / parsestr.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-22  |  7.4 KB  |  305 lines

  1. //    This is part of the iostream library, providing input/output for C++.
  2. //    Copyright (C) 1991 Per Bothner.
  3. //
  4. //    This library is free software; you can redistribute it and/or
  5. //    modify it under the terms of the GNU Library General Public
  6. //    License as published by the Free Software Foundation; either
  7. //    version 2 of the License, or (at your option) any later version.
  8. //
  9. //    This library is distributed in the hope that it will be useful,
  10. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. //    Library General Public License for more details.
  13. //
  14. //    You should have received a copy of the GNU Library General Public
  15. //    License along with this library; if not, write to the Free
  16. //    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. #pragma implementation
  19. #include "parsestr.h"
  20. #include <std.h>
  21.  
  22. streambuf* parsebuf::setbuf(char*, size_t)
  23. {
  24.     return NULL;
  25. }
  26.  
  27. int parsebuf::tell_in_line()
  28. {
  29.     return 0;
  30. }
  31.  
  32. int parsebuf::pbackfail(int c)
  33. {
  34.     if (c == EOF)
  35.     return 0;
  36.     if (seekoff(-1, ios::cur) == EOF)
  37.     return EOF;
  38.     return (unsigned char)c;
  39. }
  40.  
  41. char* parsebuf::current_line() { return NULL; }
  42.  
  43. streampos parsebuf::seekoff(streamoff offset, seek_dir dir, long)
  44. {
  45.     // Make offset relative to line start.
  46.     switch (dir) {
  47.       case ios::beg:
  48.     offset -= pos_at_line_start;
  49.     break;
  50.       case ios::cur:
  51.     offset += tell_in_line();
  52.     break;
  53.       default:
  54.     return EOF;
  55.     }
  56.     if (offset < -1)
  57.     return EOF;
  58.     if (offset > _line_length + 1)
  59.     return EOF;
  60.     return seek_in_line(offset) + pos_at_line_start;
  61. }
  62.  
  63. // string_parsebuf invariants:
  64. // The reserve ares (base() .. ebuf()) is always the entire string.
  65. // The get area (eback() .. egptr()) is the extended current line
  66. // (i.e. with the '\n' at either end, if these exist).
  67.  
  68. string_parsebuf::string_parsebuf(char *buf, size_t len,
  69.                  int delete_at_close=0)
  70. : parsebuf()
  71. {
  72.     setb(buf, buf+len, delete_at_close);
  73.     register char *ptr = buf;
  74.     while (ptr < ebuf() && *ptr != '\n') ptr++;
  75.     _line_length = ptr - buf;
  76.     setg(buf, buf, ptr);
  77. }
  78.  
  79. int string_parsebuf::underflow()
  80. {
  81.     register char* ptr = egptr(); // Point to end of current_line
  82.     do {
  83.     int i = right() - ptr;
  84.     if (i <= 0)
  85.         return EOF;
  86.     ptr++; i--; // Skip '\n'.
  87.     char *line_start = ptr;
  88.     while (ptr < right() && *ptr == '\n') ptr++;
  89.     setg(line_start-1, line_start, ptr + (ptr < right()));
  90.     pos_at_line_start = line_start - left();
  91.     _line_length = ptr - line_start;
  92.     __line_number++;
  93.     } while (gptr() == ptr);
  94.     return *gptr();
  95. }
  96.  
  97. char* string_parsebuf::current_line()
  98. {
  99.     char *ptr = eback();
  100.     if (__line_number > 0)
  101.     ptr++; // Skip '\n' at end of previous line.
  102.     return ptr;
  103. }
  104.  
  105. int string_parsebuf::tell_in_line()
  106. {
  107.     int offset = gptr() - eback();
  108.     if (__line_number > 0)
  109.     offset--;
  110.     return offset;
  111. }
  112.  
  113. int string_parsebuf::seek_in_line(int i)
  114. {
  115.     int delta = i - tell_in_line();
  116.     gbump(delta); // FIXME: Needs error (bounds) checking!
  117.     return i;
  118. }
  119.  
  120. static const char NewLine[1] = { '\n' };
  121.  
  122. general_parsebuf::general_parsebuf(streambuf *buf, int delete_arg_buf = 0)
  123.  : parsebuf()
  124. {
  125.     delete_buf = delete_arg_buf;
  126.     sbuf = buf;
  127.     int buf_size = 128;
  128.     char* buffer = new char[buf_size];
  129.     setb(buffer, buffer+buf_size, 1);
  130. //    setg(buffer, buffer, buffer);
  131. }
  132.  
  133. general_parsebuf::~general_parsebuf()
  134. {
  135.     if (delete_buf)
  136.     delete sbuf;
  137. }
  138.  
  139. int general_parsebuf::underflow()
  140. {
  141.     register char *ptr = base();
  142.     int has_newline = eback() < gptr() && gptr()[-1] == '\n';
  143.     if (has_newline)
  144.     *ptr++ = '\n';
  145.     register streambuf *sb = sbuf;
  146.     register int ch;
  147.     for (;;) {
  148.     ch = sb->sbumpc();
  149.     if (ch == EOF)
  150.         break;
  151.     if (ptr == ebuf()) {
  152.         int old_size = ebuf() - base();
  153.         char *new_buffer = new char[old_size * 2];
  154.         memcpy(new_buffer, base(), old_size);
  155.         setb(new_buffer, new_buffer + 2 * old_size, 1);
  156.         ptr = new_buffer + old_size;
  157.     }
  158.     *ptr++ = ch;
  159.     if (ch == '\n')
  160.         break;
  161.     }
  162.     char *cur_pos = base() + has_newline;
  163.     pos_at_line_start += _line_length + 1;
  164.     _line_length = ptr - cur_pos;
  165.     if (ch != EOF || _line_length > 0)
  166.     __line_number++;
  167.     setg(base(), cur_pos, ptr);
  168.     return ptr == cur_pos ? EOF : cur_pos[0];
  169. }
  170.  
  171. char* general_parsebuf::current_line()
  172. {
  173.     char* ret = base();
  174.     if (__line_number > 1)
  175.     ret++; // Move past '\n' from end of previous line.
  176.     return ret;
  177. }
  178.  
  179. int general_parsebuf::tell_in_line()
  180. {
  181.     int off = gptr() - base();
  182.     if (__line_number > 1)
  183.     off--; // Subtract 1 for '\n' from end of previous line.
  184.     return off;
  185. }
  186.  
  187. int general_parsebuf::seek_in_line(int i)
  188. {
  189.     if (__line_number == 0)
  190.     (void)general_parsebuf::underflow();
  191.     if (__line_number > 1)
  192.     i++; // Add 1 for '\n' from end of previous line.
  193.     if (i < 0) i = 0;
  194.     int len = egptr() - eback();
  195.     if (i > len) i = len;
  196.     setg(base(), base() + i, egptr());
  197.     return i;
  198. }
  199.  
  200. func_parsebuf::func_parsebuf(CharReader func, void *argm=NULL) : parsebuf()
  201. {
  202.     read_func = func;
  203.     arg = argm;
  204.     buf_start = NULL;
  205.     buf_end = NULL;
  206.     setb((char*)NewLine, (char*)NewLine+1, 0);
  207.     setg((char*)NewLine, (char*)NewLine+1, (char*)NewLine+1);
  208.     backed_up_to_newline = 0;
  209. }
  210.  
  211. int func_parsebuf::tell_in_line()
  212. {
  213.     if (buf_start == NULL)
  214.     return 0;
  215.     if (egptr() != (char*)NewLine+1)
  216.     // Get buffer was line buffer.
  217.     return gptr() - buf_start;
  218.     if (backed_up_to_newline)
  219.     return -1;  // Get buffer is '\n' preceding current line.
  220.     // Get buffer is '\n' following current line.
  221.     return (buf_end - buf_start) + (gptr() - (char*)NewLine);
  222. }
  223.  
  224. char* func_parsebuf::current_line()
  225. {
  226.     return buf_start;
  227. }
  228.  
  229. int func_parsebuf::seek_in_line(int i)
  230. {
  231.     if (i < 0) {
  232.     // Back up to preceding '\n'.
  233.     if (i < -1) i = -1;
  234.     backed_up_to_newline = 1;
  235.     setg((char*)NewLine, (char*)NewLine+(i+1), (char*)NewLine+1);
  236.     return i;
  237.     }
  238.     backed_up_to_newline = 0;
  239.     int line_length = buf_end-buf_start;
  240.     if (i <= line_length) {
  241.     setg(buf_start, buf_start+i, buf_end);
  242.     return i;
  243.     }
  244.     i -= line_length;
  245.     if (i > 0) i = 1;
  246.     setg((char*)NewLine, (char*)NewLine+i, (char*)NewLine+1);
  247.     return line_length + i;
  248. }
  249.  
  250. int func_parsebuf::underflow()
  251. {
  252.   retry:
  253.     if (gptr() < egptr())
  254.     return *gptr();
  255.     if (gptr() != (char*)NewLine+1) {
  256.     // Get buffer was line buffer.  Move to following '\n'.
  257.     setg((char*)NewLine, (char*)NewLine, (char*)NewLine+1);
  258.     return *gptr();
  259.     }
  260.     if (backed_up_to_newline)
  261.     // Get buffer was '\n' preceding current line. Move to current line.
  262.     backed_up_to_newline = 0;
  263.     else {
  264.     // Get buffer was '\n' following current line. Read new line.
  265.     if (buf_start) free(buf_start);
  266.     char *str = (*read_func)(arg);
  267.     buf_start = str;
  268.     if (str == NULL)
  269.         return EOF;
  270.     // Initially, _line_length == -1, so pos_at_line_start becomes 0.
  271.     pos_at_line_start += _line_length + 1;
  272.     _line_length = strlen(str);
  273.     buf_end = str + _line_length;
  274.     __line_number++;
  275.     }
  276.     setg(buf_start, buf_start, buf_end);
  277.     goto retry;
  278. }
  279.  
  280. #if 0
  281. size_t parsebuf::line_length()
  282. {
  283.     if (current_line_length == (size_t)(-1)) // Initial value;
  284.     (void)sgetc();
  285.     return current_line_length;
  286. }
  287. #endif
  288.  
  289. int parsebuf::seek_in_line(int i)
  290. {
  291. #if 1
  292.     abort();
  293. #else
  294.     if (i > 0) {
  295.     size_t len = line_length();
  296.     if ((unsigned)i > len) i = len;
  297.     }
  298.     else if (i < -1) i = -1;
  299.     int new_pos = seekoff(pos_at_line_start + i, ios::beg);
  300.     if (new_pos == EOF)
  301.     return tell_in_line();
  302.     else return new_pos - pos_at_line_start;
  303. #endif
  304. }
  305.